package net.oschina.bilbodai.common.beanutil.bean.annotation;

import net.oschina.bilbodai.common.beanutil.bean.PropertyDumpType;
import net.oschina.bilbodai.common.beanutil.bean.type.NullType;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import net.oschina.bilbodai.common.beanutil.bean.IBeanAccessor;
/**
 * @author daimao  Date: 16/4/20 Time: 下午6:02
 * @version $Id$
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD })
public @interface DumpProperty {

    /**
     * 如果指定,表示当{@link IBeanAccessor}是通过profile对应的值生成时,才进行属性复制 <br>
     * <pre>
     *     class TFoo{
     *         {@code @}DumpProperty(profiles="foo")
     *         private String name;
     *     }
     * </pre>
     * 表示只要当TFoo与Foo进行name字段复制时并且是通过激活profile为foo才生效配置。否则按照默认配置来
     * @return 表示当标注类型与peerType对应时,才进行属性复制
     */
    String[] profiles() default {};

    /**
     * 默认为空字符串,则会使用字段名作为唯一名。
     * 一般情况下,属性值拷贝的名字就为字段名,但是可能由于某种原因,源属性和目标属性的名称对应不上,
     * 这个时候就需要通过添加这个注解来修改属性的名称,使得源属性和目标属性能对应上。
     *
     * @return 指定属性的唯一名称而不是使用字段名
     */
    String name() default "";

    /**
     *
     * @return 是否是必须有一个属性与之对应, 如果为true, 则标识没有则抛出异常, false则忽略属性拷贝
     */
    boolean required() default false;

    /**
     * 直接从源实例的属性值中通过把 {@link DumpProperty#name()} 作为path进行查询后得到值填入目标属性
     * 例如: 源 {@code  [{"name":"alex","age":10}]} 遍历提取name 到 {@code List<String> names}
     * 注意:如果指定了attrPath,则必须指定 {@link DumpProperty#attrType()}
     * @return AttrPath
     */
    String attrPath() default "";

    /**
     * 直接从源实例的属性值中通过把 {@link DumpProperty#attrPath()} 作为path进行查询后得到值填入目标属性的属性类型
     * 例如: 源 {@code  [{"name":"alex","age":10}]} 遍历提取name 到 {@code List<String> names} 的目标属性为 {@code java.lang.String}
     *
     * @return attrType
     */
    Class<?> attrType() default NullType.class;

    /**
     * 一般情况下,
     * 如果Target属性的值不为null或者属性是原始类型时
     * 不会进行属性值拷贝.
     * 但是如果需要强制进行覆盖的话,可以设置为true
     *
     * @return 是否强制覆盖
     */
    boolean forceDump() default false;

    /**
     * 源属性类型
     *
     * @return 参见 {@link PropertyDumpType}
     */
    PropertyDumpType srcDumpType() default PropertyDumpType.NONE;

    /**
     * @return 源集合的元素类型, Collection中指元素的类型, Map中指值类型, 一般用于字段没有显示声明泛型的情况
     */
    Class<?> srcComponentType() default NullType.class;

    /**
     * @return 源Map的键类型, 一般用于字段没有显示声明泛型的情况
     */
    Class<?> srcKeyType() default NullType.class;

    /**
     * 目标属性类型
     *
     * @return 参见 {@link PropertyDumpType}
     */
    PropertyDumpType targetDumpType() default PropertyDumpType.NONE;

    /**
     * @return 目标集合的元素类型, Collection中指元素的类型, Map中指值类型, 一般用于字段没有显示声明泛型的情况
     */
    Class<?> targetComponentType() default NullType.class;

    /**
     * 当Collection{@code <Foo>}转Map的时候,Map需要知道用什么做key,这个字段就是Foo里的字段名
     * @return 转Map时显示告知用哪个元素的字段值做key
     */
    String mapFieldName() default "";

    /**
     * @return 目标Map的键类型, 一般用于字段没有显示声明泛型的情况
     */
    Class<?> targetKeyType() default NullType.class;

    /**
     * @return 目标字段类型的实现类型, 集合类型中如果未指定, 那么采用 {@link PropertyDumpType#typeImpl}
     */
    Class<?> collectTypeImpl() default NullType.class;

    boolean sorted() default false;
}